/*
 * Copyright 2018- The Pixie Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

syntax = "proto3";

package px.carnot.planner.plannerpb;

option go_package = "plannerpb";

import "src/carnot/planner/dynamic_tracing/ir/logicalpb/logical.proto";
import "src/common/base/statuspb/status.proto";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
import "src/carnot/planner/distributedpb/distributed_plan.proto";

// FuncToExecute specifies the name and arguments of a function to execute.
message FuncToExecute {
  // Name of function to execute.
  string func_name = 1;
  message ArgValue {
    // name of the argument.
    string name = 1;
    // value of the argument as a string.
    // Compiler will attempt to parse the string as the type expected.
    // eg. a value of "1" for a function expecting an int would parse to 1,
    // but the same value for a function expecting a string would parse to "1".
    // In the future, we could also support parsing of expressions here, but
    // this would require doing something along the lines of "'string literal'" for string.
    string value = 2;
  }
  // arg_values are the arguments to the function. If arg_values do not match
  // the signature of the function, then the ExecuteScriptResponse will return
  // an error stating this issue. Arg_values will not match if
  //   1. arg_values misses any parameters to `func_name`
  //   2. arg_values adds parameters to `func_name`.
  //   3. the value in arg_value doesn't parse to the expected type.
  repeated ArgValue arg_values = 2;
  // output_table_prefix is the prefix of the name of the table that is returned in the response.
  // If the function returns a dataframe, then the table name will be `format("%s",
  // output_table_prefix)`. If the function returns a list of dataframes (even if the list is of
  // length 1), then the table names will be `format("%s[%d]", output_table_prefix, index)`.
  string output_table_prefix = 3;
}

// Configs specifies extra configuration to be given to the provider. For example,
// endpoint information that should be used across all OTel exports.
message Configs {
  // OTelEndpointConfig contains information about which OTelEndpoint + headers should be attached
  // to all OTel export calls in the script.
  message OTelEndpointConfig {
    string url = 1 [ (gogoproto.customname) = "URL" ];
    map<string, string> headers = 2;
    bool insecure = 3;
    int64 timeout = 4;
  }
  OTelEndpointConfig otel_endpoint_config = 1 [ (gogoproto.customname) = "OTelEndpointConfig" ];
  message PluginConfig {
    // The start_time of the script in nanoseconds.
    int64 start_time_ns = 1;
    // The end_time of the script in nanoseconds.
    int64 end_time_ns = 2;
  }
  PluginConfig plugin_config = 2;
}

// QueryRequest is the body of the request made to the planner.
message QueryRequest {
  px.carnot.planner.distributedpb.LogicalPlannerState logical_planner_state = 5;
  // query_str is the string representation of the query to run.
  string query_str = 1;
  // exec_funcs is a list of functions to execute.
  // If any functions specified cannot be found the planner will return a compiler error.
  repeated FuncToExecute exec_funcs = 3;
  // Configs specifies extra configuration to be given to the compiler.
  Configs configs = 4;
  // TODO(zasgar): Add proto query.
  reserved 2;
}

// QueryResponse contains the plan or status of the query.
message QueryResponse {
  // The Status of the Query Request. Holds an error with debug
  // information if the originating request had a bug, otherwise will be set to
  // OK.
  px.statuspb.Status status = 1;
  px.carnot.planner.distributedpb.DistributedPlan plan = 2;
}

// CompileMutationRequest represents any request that compiles to a mutation of
// Pixie internal data state.
message CompileMutationsRequest {
  px.carnot.planner.distributedpb.LogicalPlannerState logical_planner_state = 5;
  // The pxl script to run that compiles into a mutation
  string query_str = 1;
  // exec_funcs is a list of functions to execute.
  // If any functions specified cannot be found the planner will return a compiler error.
  repeated FuncToExecute exec_funcs = 3;
  // Configs specifies extra configuration to be given to the compiler.
  Configs configs = 4;
}

// DeleteTracepoint is a mutation that deletes a tracepoint running on Vizier.
message DeleteTracepoint {
  // The name of the Tracepoint to delete.
  string name = 1;
}

// ConfigUpdate contains info about an update for a particular agent in Vizier.
message ConfigUpdate {
  // Key is the attribute of the config to update with the value.
  string key = 1;
  // Value to set for the key in the config.
  string value = 2;
  // The pod name of the agent that will receive this config update.
  string agent_pod_name = 3;
}

// The definition of a mutation to perfom on Vizier. Mutations include operations
// that add and delete tables to the database.
message CompileMutation {
  oneof mutation {
    // Trace contains the compiled Dynamic Trace definition passed in by the
    // request.
    carnot.planner.dynamic_tracing.ir.logical.TracepointDeployment trace = 2;
    // Mutation that deletes a tracepoint.
    DeleteTracepoint delete_tracepoint = 3;
    // Mutation that sets a config.
    ConfigUpdate config_update = 4;
  }
}

// CompileMutationsResponse holds the mutations compiled by the planner.
message CompileMutationsResponse {
  // The Status of the Mutation Compilation Request. Holds an error with debug
  // information if the originating request had a bug, otherwise will be set to
  // OK.
  px.statuspb.Status status = 1;
  // The set of mutations to run on the Vizier.
  repeated CompileMutation mutations = 2;
}

message GenerateOTelScriptRequest {
  px.carnot.planner.distributedpb.LogicalPlannerState logical_planner_state = 1;
  string pxl_script = 2;
}

message GenerateOTelScriptResponse {
  // The Status of GenerateOTelScript. Holds an error with debug
  // information if the originating request had a bug, otherwise will be set to
  // OK.
  px.statuspb.Status status = 1;
  string otel_script = 2 [ (gogoproto.customname) = "OTelScript" ];
}

service PlannerService {
  // CompileQuery compiles a query into a set of logical plans.
  rpc CompileQuery(QueryRequest) returns (QueryResponse);
  // CompileMutations compiles a set of mutations into a set of logical plans.
  rpc CompileMutations(CompileMutationsRequest) returns (CompileMutationsResponse);
  // GenerateOTelScript generates an OTel script from a PXL script.
  rpc GenerateOTelScript(GenerateOTelScriptRequest) returns (GenerateOTelScriptResponse);
}
